/*
*
* This file is part of QMapControl,
* an open-source cross-platform map widget
*
* Copyright (C) 2007 - 2008 Kai Winter
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with QMapControl. If not, see <http://www.gnu.org/licenses/>.
*
* Contact e-mail: kaiwinter@gmx.de
* Program URL   : http://qmapcontrol.sourceforge.net/
*
*/

#include "mapcontrol.h"
namespace qmapcontrol
{
	MapControl::MapControl(QSize size, MouseMode mousemode)
	: size(size), mymousemode(mousemode), scaleVisible(false)
	{
		layermanager = new LayerManager(this, size);
		screen_middle = QPoint(size.width()/2, size.height()/2);
	
		mousepressed = false;
	
		connect(ImageManager::instance(), SIGNAL(imageReceived()),
				  this, SLOT(updateRequestNew()));
	
		connect(ImageManager::instance(), SIGNAL(loadingFinished()),
				  this, SLOT(loadingFinished()));
	
		this->setMaximumSize(size.width()+1, size.height()+1);
	}

	MapControl::~MapControl()
	{
		delete layermanager;	
	}

	QPointF	MapControl::currentCoordinate() const
	{
		return layermanager->currentCoordinate();
	}

	Layer* MapControl::layer(const QString& layername) const
	{
		return layermanager->layer(layername);
	}

	QList<QString> MapControl::layers() const
	{
		return layermanager->layers();
	}

	int MapControl::numberOfLayers() const
	{
		return layermanager->layers().size();
	}

	void MapControl::followGeometry(const Geometry* geom) const
	{
		connect(geom, SIGNAL(positionChanged(Geometry*)),
				  this, SLOT(positionChanged(Geometry*)));
	}

	void MapControl::positionChanged(Geometry* geom)
	{
		QPoint start = layermanager->layer()->mapadapter()->coordinateToDisplay(currentCoordinate());
		QPoint dest = layermanager->layer()->mapadapter()->coordinateToDisplay(((Point*)geom)->coordinate());

		QPoint step = (dest-start);

		layermanager->scrollView(step);
	
// 	setView(geom);
		update();
	}

	void MapControl::moveTo(QPointF coordinate)
	{
		target = coordinate;
		steps = 25;
		if (moveMutex.tryLock())
		{
			QTimer::singleShot(40, this, SLOT(tick()));	
		}
		else
		{
// 		stopMove(coordinate);
		}
	}
	void MapControl::tick()
	{
		QPoint start = layermanager->layer()->mapadapter()->coordinateToDisplay(currentCoordinate());
		QPoint dest = layermanager->layer()->mapadapter()->coordinateToDisplay(target);
	
		QPoint step = (dest-start)/steps;
		QPointF next = currentCoordinate()- step;

// 	setView(Coordinate(next.x(), next.y()));
		layermanager->scrollView(step);
	
		update();
		steps--;
		if (steps>0)
		{
			QTimer::singleShot(40, this, SLOT(tick()));
		}
		else
		{
			moveMutex.unlock();
		}
	}

	void MapControl::paintEvent(QPaintEvent* evnt)
	{
		QWidget::paintEvent(evnt);
		QPainter painter(this);
	
// 	painter.translate(150,190);
// 	painter.scale(0.5,0.5);
	
// 	painter.setClipRect(0,0, size.width(), size.height());
	
// 	painter.setViewport(10000000000,0,size.width(),size.height());
	
	/*
	// rotating
		rotation = 45;
		painter.translate(256,256);
		painter.rotate(rotation);
		painter.translate(-256,-256);
	*/

		layermanager->drawImage(&painter);
		layermanager->drawGeoms(&painter);
		
		// added by wolf
		// draw scale
		if (scaleVisible)
		{
			QList<double> distanceList;
			distanceList<<5000000<<2000000<<1000000<<1000000<<1000000<<100000<<100000<<50000<<50000<<10000<<10000<<10000<<1000<<1000<<500<<200<<100<<50<<25;
			if (currentZoom() >= 0 && distanceList.size() > currentZoom())
			{
				double line;
				line = distanceList.at( currentZoom() ) / pow(2, 18-currentZoom() ) / 0.597164;
			
				// draw the scale
				painter.setPen(Qt::black);
				QPoint p1(10,size.height()-20);
				QPoint p2((int)line,size.height()-20);
				painter.drawLine(p1,p2);
		
				painter.drawLine(10,size.height()-15, 10,size.height()-25); 
				painter.drawLine((int)line,size.height()-15, (int)line,size.height()-25); 
				
				QString distance;
				if (distanceList.at(currentZoom()) >= 1000) 
				{
					distance = QVariant( distanceList.at(currentZoom())/1000 )  .toString()+ " km";
				}
				else
				{
					distance = QVariant( distanceList.at(currentZoom()) ).toString() + " m";
				}
		
				painter.drawText(QPoint((int)line+10,size.height()-15), distance);
			}
		}
		
		
	
		painter.drawLine(screen_middle.x(), screen_middle.y()-10,
							  screen_middle.x(), screen_middle.y()+10); // |
		painter.drawLine(screen_middle.x()-10, screen_middle.y(),
							  screen_middle.x()+10, screen_middle.y()); // -
	
// 	int cross_x = int(layermanager->getMapmiddle_px().x())%256;
// 	int cross_y = int(layermanager->getMapmiddle_px().y())%256;
// 	painter.drawLine(screen_middle.x()-cross_x+cross_x, screen_middle.y()-cross_y+0,
// 						  screen_middle.x()-cross_x+cross_x, screen_middle.y()-cross_y+256); // |
// 	painter.drawLine(screen_middle.x()-cross_x+0, screen_middle.y()-cross_y+cross_y,
// 						  screen_middle.x()-cross_x+256, screen_middle.y()-cross_y+cross_y); // -
	
		painter.drawRect(0,0, size.width(), size.height());
	/*
	// rotating
		painter.setMatrix(painter.matrix().inverted());
	//qt = painter.transform();
		qm = painter.combinedMatrix();
	*/

		if (mousepressed && mymousemode == Dragging)
		{
			QRect rect = QRect(pre_click_px, current_mouse_pos);
			painter.drawRect(rect);
		}
		emit viewChanged(currentCoordinate(), currentZoom());
	}

// mouse events
	void MapControl::mousePressEvent(QMouseEvent* evnt)
	{
	//rotating
	
// 	QMouseEvent* me = new QMouseEvent(evnt->type(), qm.map(QPoint(evnt->x(),evnt->y())), evnt->button(), evnt->buttons(), evnt->modifiers());
// 	evnt = me;
// 	qDebug() << "evnt: " << evnt->x() << ", " << evnt->y() << ", " << evnt->pos();

	
		layermanager->mouseEvent(evnt);
	
		if (layermanager->layers().size()>0)
		{
			if (evnt->button() == 1)
			{
				mousepressed = true;
				pre_click_px = QPoint(evnt->x(), evnt->y());
			}
			else if (evnt->button() == 2 && mymousemode != None)	// zoom in
			{
				zoomIn();
			} else if  (evnt->button() == 4 && mymousemode != None)	// zoom out
			{
				zoomOut();
			}
		}
	
// 	emit(mouseEvent(evnt));
		emit(mouseEventCoordinate(evnt, clickToWorldCoordinate(evnt->pos())));
	}

	void MapControl::mouseReleaseEvent(QMouseEvent* evnt)
	{
		mousepressed = false;
		if (mymousemode == Dragging)
		{
			QPointF ulCoord = clickToWorldCoordinate(pre_click_px);
			QPointF lrCoord = clickToWorldCoordinate(current_mouse_pos);
		
			QRectF coordinateBB = QRectF(ulCoord, QSizeF( (lrCoord-ulCoord).x(), (lrCoord-ulCoord).y()));

			emit(boxDragged(coordinateBB));
		}
	
		emit(mouseEventCoordinate(evnt, clickToWorldCoordinate(evnt->pos())));
	}

	void MapControl::mouseMoveEvent(QMouseEvent* evnt)
	{
// 	emit(mouseEvent(evnt));
	
	/*
	// rotating
		QMouseEvent* me = new QMouseEvent(evnt->type(), qm.map(QPoint(evnt->x(),evnt->y())), evnt->button(), evnt->buttons(), evnt->modifiers());
		evnt = me;
	*/
		if (mousepressed && mymousemode == Panning)
		{
			QPoint offset = pre_click_px - QPoint(evnt->x(), evnt->y());
			layermanager->scrollView(offset);
			pre_click_px = QPoint(evnt->x(), evnt->y());
		}
		else if (mousepressed && mymousemode == Dragging)
		{
			current_mouse_pos = QPoint(evnt->x(), evnt->y());
		}
// 	emit(mouseEventCoordinate(evnt, clickToWorldCoordinate(evnt->pos())));

		update();
// 	emit(mouseEventCoordinate(evnt, clickToWorldCoordinate(evnt->pos())));
	}

        void MapControl::wheelEvent(QWheelEvent *evnt)
        {
            int numDegrees = evnt->delta() / 8;
            int numSteps = numDegrees / 15;

            if (numSteps > 0){
                for (int i = 0; i < numSteps; ++i)
                    zoomIn();
            } else {
                for (int i = 0; i < qAbs(numSteps); ++i)
                    zoomOut();
            }
            evnt->accept();
        }

	QPointF MapControl::clickToWorldCoordinate(QPoint click)
	{
	// click coordinate to image coordinate
		QPoint displayToImage= QPoint(click.x()-screen_middle.x()+layermanager->getMapmiddle_px().x(),
												click.y()-screen_middle.y()+layermanager->getMapmiddle_px().y());
	// image coordinate to world coordinate
		return layermanager->layer()->mapadapter()->displayToCoordinate(displayToImage);
	}

	void MapControl::updateRequest(QRect rect)
	{
		update(rect);
	}
	void MapControl::updateRequestNew()
	{
// 	qDebug() << "MapControl::updateRequestNew()";
		layermanager->forceRedraw();
		update();
	}
// slots
	void MapControl::zoomIn()
	{
		layermanager->zoomIn();
		update();
	}
	void MapControl::zoomOut()
	{
		layermanager->zoomOut();
		update();
	}
	void MapControl::setZoom(int zoomlevel)
	{
		layermanager->setZoom(zoomlevel);
		update();
	}
	int MapControl::currentZoom() const
	{
		return layermanager->currentZoom();
	}
	void MapControl::scrollLeft(int pixel)
	{
		layermanager->scrollView(QPoint(-pixel,0));
		update();
	}
	void MapControl::scrollRight(int pixel)
	{
		layermanager->scrollView(QPoint(pixel,0));
		update();
	}
	void MapControl::scrollUp(int pixel)
	{
		layermanager->scrollView(QPoint(0,-pixel));
		update();
	}
	void MapControl::scrollDown(int pixel)
	{
		layermanager->scrollView(QPoint(0,pixel));
		update();
	}
	void MapControl::scroll(const QPoint scroll)
	{
		layermanager->scrollView(scroll);
		update();
	}

	void MapControl::setView(const QPointF& coordinate) const
	{
		layermanager->setView(coordinate);
	}

	void MapControl::setView(const QList<QPointF> coordinates) const
	{
		layermanager->setView(coordinates);
	}

	void MapControl::setViewAndZoomIn(const QList<QPointF> coordinates) const
	{
		layermanager->setViewAndZoomIn(coordinates);
	}

	void MapControl::setView(const Point* point) const
	{
		layermanager->setView(point->coordinate());
	}

	void MapControl::loadingFinished()
	{
// 	qDebug() << "MapControl::loadingFinished()";
		layermanager->removeZoomImage();
	}
	void MapControl::addLayer(Layer* layer)
	{
		layermanager->addLayer(layer);
	}

	void MapControl::setMouseMode(MouseMode mousemode)
	{
		mymousemode = mousemode;
	}
	MapControl::MouseMode MapControl::mouseMode()
	{
		return mymousemode;
	}

	void MapControl::stopFollowing(Geometry* geom)
	{
		geom->disconnect(SIGNAL(positionChanged(Geometry*)));
	}
	
	void MapControl::enablePersistentCache(const QDir& path)
	{
		ImageManager::instance()->setCacheDir(path);
	}
	
	void MapControl::setProxy(QString host, int port)
	{
		ImageManager::instance()->setProxy(host, port);
	}
	
	void MapControl::showScale(bool show)
	{
		scaleVisible = show;
	}
	
	void MapControl::resize(const QSize newSize)
	{
		this->size = newSize;
		screen_middle = QPoint(newSize.width()/2, newSize.height()/2);
	
		this->setMaximumSize(newSize.width()+1, newSize.height()+1);
		layermanager->resize(newSize);
	}
}
